package com.itheima.pinda.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.pinda.DTO.base.GoodsTypeDto;
import com.itheima.pinda.common.utils.Constant;
import com.itheima.pinda.common.utils.PageResponse;
import com.itheima.pinda.entity.PdGoodsType;
import com.itheima.pinda.entity.PdTruckTypeGoodsType;
import com.itheima.pinda.mapper.PdGoodsTypeMapper;
import com.itheima.pinda.mapstruct.GoodsDTO2Entity;
import com.itheima.pinda.service.PdGoodsTypeService;
import com.itheima.pinda.service.PdTruckTypeGoodsTypeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
public class PdGoodsTypeServiceImpl extends ServiceImpl<PdGoodsTypeMapper, PdGoodsType> implements PdGoodsTypeService {


    @Resource
    private PdTruckTypeGoodsTypeService truckTypeGoodsTypeService;

    @Resource
    private PdGoodsTypeMapper pdGoodsTypeMapper;

    @Resource
    private GoodsDTO2Entity goodsDTO2Entity;

    /**
     * 新增货物类型, 同时要关联中间表车辆类型 pd_truck_type_goods_type 插入一条数据
     *
     * @param dto 货物类型信息
     * @return 货物类型信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public GoodsTypeDto saveGoodsType(GoodsTypeDto dto) {
        // 1.保存到货物类型信息到货物表
        // PdGoodsType pdGoodsType = new PdGoodsType();
        // BeanUtils.copyProperties(dto, pdGoodsType);
        PdGoodsType pdGoodsType = goodsDTO2Entity.conver(dto);
        boolean save = super.save(pdGoodsType);
        if (!save) {
            throw new RuntimeException("新增货物类型失败!");
        }

        // 2.保存货物类型和车辆关联信息到关联表
        // todo 是否重构DTO的 主键类型为 Long 类型
        List<String> truckTypeIds = dto.getTruckTypeIds();
        if (truckTypeIds != null && truckTypeIds.size() > 0) {
            List<PdTruckTypeGoodsType> list = truckTypeIds.stream()
                    .map(truckId -> PdTruckTypeGoodsType.builder()
                            .truckTypeId(truckId)               // 车辆Id
                            .goodsTypeId(pdGoodsType.getId() + "")   // 货物类型id
                            .build())
                    .collect(Collectors.toList());

            truckTypeGoodsTypeService.batchSave(list);
        }

        // 使用BeanUtils.copy 将 PdGoodsType的属性拷贝到 dto, 这个dto一开始是没有id的
        // 经过mp的保存操作之后, 会自动将id会写到对象中
        // bug点: BeanUtils. 能否拷贝到pdGoodsType父类的id属性
        // fix: 使用MapStruct来做属性的映射, 需要加一个注解@Mapper(builder = @Builder(disableBuilder = true))
        // 不是用构建者模式来创建对象, 否则会导致 MapStruct build模式会丢失父类的属性
        // BeanUtils.copyProperties(pdGoodsType, dto);
        // dto.setId(pdGoodsType.getId() + "");
        dto = goodsDTO2Entity.conver(pdGoodsType);
        log.info("pdGoodsType: {}", pdGoodsType);
        return dto;
    }


    /**
     * 根据id查询货物类型
     *
     * @param id 货物类型id
     * @return GoodsTypeDto
     */
    @Override
    public GoodsTypeDto findById(String id) {
        PdGoodsType pdGoodsType = super.getById(id);
        GoodsTypeDto dto = new GoodsTypeDto();
        if (pdGoodsType != null) {
            dto = goodsDTO2Entity.conver(pdGoodsType);
            // 查询当前货物类型关联的车辆类型id
            dto.setTruckTypeIds(truckTypeGoodsTypeService.findAll(null, id)
                    .stream()
                    .map(PdTruckTypeGoodsType::getTruckTypeId)
                    .collect(Collectors.toList()));
        }

        return dto;
    }


    /**
     * 查询所有货物类型
     *
     * @return 货物类型列表
     */
    @Override
    public List<GoodsTypeDto> findGoodsAll() {
        List<PdGoodsType> pdGoodsTypeList = super.list(Wrappers.<PdGoodsType>lambdaQuery()
                .eq(PdGoodsType::getStatus, 1));

        List<GoodsTypeDto> dtoList = pdGoodsTypeList.stream()
                .map(item -> goodsDTO2Entity.conver(item))
                .collect(Collectors.toList());

        log.info("GoodsTypeDto : {}", dtoList);
        return dtoList;
    }

    /**
     * 获取货物类型列表
     *
     * @param ids 货物类型id集合
     * @return 货物类型列表
     */
    @Override
    public List<GoodsTypeDto> findGoodsAll(List<String> ids) {
        LambdaQueryWrapper<PdGoodsType> in = new LambdaQueryWrapper<>();
        if ((ids != null && ids.size() > 0)) {
            in = Wrappers.<PdGoodsType>lambdaQuery().in(PdGoodsType::getId, ids);
        }
        List<PdGoodsType> pdGoodsTypeList = baseMapper.selectList(in);
        return pdGoodsTypeList.stream().map(item -> {
            GoodsTypeDto dto = goodsDTO2Entity.conver(item);
            dto.setTruckTypeIds(truckTypeGoodsTypeService.findAll(null, dto.getId())
                    .stream()
                    .map(PdTruckTypeGoodsType::getTruckTypeId)
                    .collect(Collectors.toList()));
            return dto;
        }).collect(Collectors.toList());
    }

    /**
     * 获取分页货物类型数据
     *
     * @param page          页码
     * @param pageSize      页尺寸
     * @param name          货物类型名称
     * @param truckTypeId   车辆类型Id
     * @param truckTypeName 车辆类型名称
     * @return 货物类型分页列表
     */
    @Override
    public PageResponse<GoodsTypeDto> findByPage(Integer page, Integer pageSize, String name,
                                                 String truckTypeId, String truckTypeName) {
        Page<PdGoodsType> iPage = new Page<>(page, pageSize);
        iPage.addOrder(OrderItem.asc("id"));
        IPage<PdGoodsType> goodsTypeIPage = pdGoodsTypeMapper.findByPage(iPage, name, truckTypeId, truckTypeName);
        List<GoodsTypeDto> goodsTypeDtoList = goodsTypeIPage.getRecords()
                .stream()
                .map(goodsType -> {
                    GoodsTypeDto dto = goodsDTO2Entity.conver(goodsType);
                    dto.setTruckTypeIds(truckTypeGoodsTypeService.findAll(null, dto.getId())
                            .stream()
                            .map(PdTruckTypeGoodsType::getTruckTypeId)
                            .collect(Collectors.toList()));
                    return dto;
                }).collect(Collectors.toList());

        PageResponse<GoodsTypeDto> pageResponse = PageResponse.<GoodsTypeDto>builder()
                .items(goodsTypeDtoList)
                .counts(goodsTypeIPage.getTotal())
                .page(page)
                .pages(goodsTypeIPage.getPages())
                .pagesize(pageSize)
                .build();


        log.info("=====分页结果: {}", pageResponse);
        return pageResponse;
    }

    /**
     * 更新货物类型信息
     * 如果字段没有值, mp只会更新的值的字段, 是一种增量更新, 不是全量更新
     *
     * @param id  货物id
     * @param dto 货物类型信息
     * @return 货物类型信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public GoodsTypeDto updateGoods(String id, GoodsTypeDto dto) {
        dto.setId(id);
        PdGoodsType pdGoodsType = goodsDTO2Entity.conver(dto);
        super.updateById(pdGoodsType);
        if (dto.getTruckTypeIds() != null) {
            truckTypeGoodsTypeService.delete(null, id);

            truckTypeGoodsTypeService.batchSave(dto.getTruckTypeIds()
                    .stream()
                    .map(truckTypeId -> PdTruckTypeGoodsType.builder()
                            .goodsTypeId(id)
                            .truckTypeId(truckTypeId).build())
                    .collect(Collectors.toList())
            );
        }
        // todo, 即是前端想在更新完, 想要获取更新后的数据, 那就再查一次
        return this.findById(dto.getId());
    }

    /**
     * 删除货物类型  -> 逻辑删除
     *
     * @param id 货物类型id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteGoodsById(String id) {
        PdGoodsType pdGoodsType = new PdGoodsType();
        pdGoodsType.setId(Long.parseLong(id));
        pdGoodsType.setStatus(Constant.DATA_DISABLE_STATUS);
        super.updateById(pdGoodsType);
    }
}
